export type CountdownTime = number

export interface ICountdownTime {
  /**开始时间*/
  countdownStartTime: CountdownTime
  /**当前戳时间*/
  countdownTimeSpan: CountdownTime
  /**定时引用*/
  countdownInterval: NodeJS.Timeout | null

  countdownMaxTimeSpan: CountdownTime
  get getCountdownStartTime(): CountdownTime
  set setCountdownStartTime(re: CountdownTime)
  clearInterval: () => void
  reflashInterval: () => void
  reset: () => void
  startTime: () => void
}
export enum EFnCallBackType {
  /**开始 */
  start = 'start',
  /**间隔 */
  every1s = 'every1s',
  /**完成 */
  finish = 'finish',
}

export type CallBackHandel<P> = {
  /**开始 */
  [EFnCallBackType.start]: (re?: P) => void
  /**每一秒执行一次 */
  [EFnCallBackType.every1s]: (time: CountdownTime, re?: P) => void
  /**完成 */
  [EFnCallBackType.finish]: (time: CountdownTime, re?: P) => void
}

/**事件上下文钩子 */
export type CountdownFnCallBack<P, T> = {
  /**上下文 */
  content?: P
  fn?: ThisType<P & T> & CallBackHandel<P>
}

/**定时器 */
export class Countdown<P> implements ICountdownTime {
  /**时间记录 */
  countdownStartTime = 0
  countdownTimeSpan = 0
  countdownMaxTimeSpan = 0
  countdownInterval: NodeJS.Timeout = <NodeJS.Timeout>(<unknown>null)
  countdownFnCallback: CountdownFnCallBack<P, ICountdownTime> = {}

  /**
   *
   * @param min 分钟
   * @param countdownFn  事件上下文钩子
   */
  constructor(min: number, countdownFn: CountdownFnCallBack<P, ICountdownTime>) {
    this.countdownMaxTimeSpan = min
    this.countdownFnCallback = countdownFn
  }
  get getCountdownStartTime(): number {
    return this.countdownStartTime
  }
  set setCountdownStartTime(re: number) {
    this.countdownStartTime = re
  }
  /**开始计时 */
  startTime = () => {
    this.countdownStartTime = Date.now()
    this.reflashInterval()
    const re = this.countdownFnCallback
    if (re.fn) {
      re.fn[EFnCallBackType.start](re.content)
    }
  }
  /**重置 */
  reset = () => {
    clearTimeout(this.countdownInterval)
    this.countdownTimeSpan = 0
    this.countdownStartTime = 0
  }

  /**
   * clearInterval 清理
   */
  clearInterval = () => {
    clearTimeout(this.countdownInterval)
  }
  /**轮训 */
  reflashInterval = () => {
    this.countdownInterval = setTimeout(() => {
      const re = this.countdownFnCallback
      if (re.fn) {
        if (this.countdownTimeSpan <= this.countdownMaxTimeSpan) {
          this.countdownTimeSpan += 1000
          re.fn[EFnCallBackType.every1s](this.countdownTimeSpan, re.content)
          this.reflashInterval()
        } else {
          const d = Date.now()
          re.fn[EFnCallBackType.finish](d, re.content)
          this.clearInterval()
        }
      }
    }, 1000)
  }
}
